// 蜂窝蜜造平台生成代码，如手工更改，请添加到 .beeignore 忽略生成

package com.fowo.api.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fowo.api.common.annotaion.DataObjectType;
import com.fowo.api.common.config.CacheConfig;
import com.fowo.api.common.excel.ExcelConfig;
import com.fowo.api.common.model.OptionItem;
import com.fowo.api.common.util.ResponseUtils;
import com.fowo.api.entity.QualityCheckStorage;
import com.fowo.api.flow.entity.WorkFlow;
import com.fowo.api.flow.service.WorkFlowService;
import com.fowo.api.inventory.model.InventoryExchangeVo;
import com.fowo.api.inventory.model.InventoryStorageVo;
import com.fowo.api.inventory.model.PatternEnum;
import com.fowo.api.inventory.model.SimpleInventoryItem;
import com.fowo.api.inventory.model.TargetTypeEnum;
import com.fowo.api.inventory.model.form.InventoryExchangeFormVo;
import com.fowo.api.inventory.model.form.InventoryStorageFormVo;
import com.fowo.api.inventory.service.InventoryBusinessService;
import com.fowo.api.mapper.QualityCheckStorageMapper;
import com.fowo.api.model.quality.check.storage.QualityCheckStorageItemVo;
import com.fowo.api.model.quality.check.storage.QualityCheckStorageRevocationAction;
import com.fowo.api.model.quality.check.storage.QualityCheckStorageSearchParamPo;
import com.fowo.api.model.quality.check.storage.QualityCheckStorageVo;
import com.fowo.api.service.QualityCheckStorageService;
import com.fowo.api.sys.annotation.DataActivity;
import com.fowo.api.sys.component.ExecuteScriptEngine;
import com.fowo.api.sys.entity.enums.SysDataActivityAction;
import com.fowo.api.sys.model.NewSerialRequest;
import com.fowo.api.sys.service.SysSerialService;
import com.fowo.api.user.model.JwtUserInfo;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

/**
 * 质检单 服务实现基类
 * @author 蜂窝蜜造平台 配置人：鹿丙涛，王坤
 */
@Slf4j
@DataObjectType(QualityCheckStorage.class)
@DS("ds24")
public class QualityCheckStorageBaseServiceImpl
  extends ServiceImpl<QualityCheckStorageMapper, QualityCheckStorage>
  implements QualityCheckStorageService {

  /** 引用字段排序字段名转换信息 */
  public static final Map<String, String> SORT_FIELD_MAP = new HashMap<>() {
    {
      put("productNameName", "p.`name`");
      put("shopShopName", "si.`shop_name`");
      put("purchaseCodePurchaseOrderCode", "po.`purchase_order_code`");
      put("buyerNameName", "su.`name`");
      put("receiveNameName", "su2.`name`");
      put("warehouseName", "w.`name`");
      put("supplierSupplierName", "s.`supplier_name`");
      put("qcNameName", "su3.`name`");
      put("whbCodeGoodIdStorageBin", "wb.`storage_bin`");
      put("whbCodeBadIdStorageBin", "wb2.`storage_bin`");
      put("receiptProductIdSku", "rp.`sku`");
      put("waitInspectionStorageBin", "wb3.`storage_bin`");
    }
  };

  /**
   * 服务自引用，用于调用服务方法时包括 AOP 处理
   */
  @Resource
  protected QualityCheckStorageService self;

  @Resource
  protected SysSerialService sysSerialService;

  @Resource
  protected WorkFlowService workFlowService;

  @Autowired(required = false)
  protected QualityCheckStorageRevocationAction qualityCheckStorageRevocationAction;

  @Resource
  private ExecuteScriptEngine executeScriptEngine;

  @Resource
  protected InventoryBusinessService inventoryBusinessService;

  @Resource
  protected Validator validator;

  /**
   * 创建质检单
   * @param model 质检单
   * @return 新数据的主键
   */
  @DataActivity(action = SysDataActivityAction.Add)
  @Transactional(rollbackFor = Exception.class)
  @Override
  public Long create(QualityCheckStorageVo model) throws Exception {
    JwtUserInfo currentUser = JwtUserInfo.fromHeader();
    QualityCheckStorage entity = new QualityCheckStorage();
    BeanUtils.copyProperties(model, entity);
    entity.setCreateTime(new Date());
    entity.setLastUpdateTime(new Date());
    if (currentUser != null) {
      entity.setCreateUser(currentUser.getUserId());
      entity.setLastUpdateUser(currentUser.getUserId());
    }

    if (model.getQcMethodType() == null) {
      entity.setQcMethodType("1");
    }

    if (model.getQcStatus() == null) {
      entity.setQcStatus("0");
    }

    if (model.getIsPrint() == null) {
      entity.setIsPrint("0");
    }

    if (model.getEntryLibrary() == null) {
      entity.setEntryLibrary(1);
    }

    if (model.getIsUrgent() == null) {
      entity.setIsUrgent("0");
    }
    // 填充序列号
    if (!StringUtils.hasText(entity.getQcSn())) {
      entity.setQcSn(
        sysSerialService.getNewSerial(
          new NewSerialRequest(null, "QualityCheckStorage.qcSn")
        )
      );
    }
    // 填充序列号
    if (!StringUtils.hasText(entity.getOrderSn())) {
      entity.setOrderSn(
        sysSerialService.getNewSerial(
          new NewSerialRequest(null, "QualityCheckStorage.orderSn")
        )
      );
    }
    if (this.save(entity)) {
      return entity.getId();
    }
    throw new Exception("质检单保存失败");
  }

  /**
   * 更新质检单
   * @param model 质检单
   * @return 更新是否成功
   */
  @DataActivity(action = SysDataActivityAction.Modified)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean update(QualityCheckStorageVo model) throws Exception {
    JwtUserInfo currentUser = JwtUserInfo.fromHeader();
    QualityCheckStorage entity = this.getById(model.getId());
    if (entity == null) {
      throw new Exception("质检单不存在");
    }
    BeanUtils.copyProperties(
      model,
      entity,
      "id",
      "productImg",
      "createTime",
      "isPrint",
      "createUser",
      "lastUpdateTime",
      "lastUpdateUser",
      "classifyId"
    );
    entity.setLastUpdateTime(new Date());
    if (currentUser != null) {
      entity.setLastUpdateUser(currentUser.getUserId());
    }
    if (this.updateById(entity)) {
      return true;
    }
    return false;
  }/**
   * 更新质检单（带空值）
   * @param model 质检单
   * @return 更新是否成功
   */

  @DataActivity(action = SysDataActivityAction.Modified)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean updateForEdit(QualityCheckStorageVo model) throws Exception {
    JwtUserInfo currentUser = JwtUserInfo.fromHeader();
    QualityCheckStorage entity = this.getById(model.getId());
    if (entity == null) {
      throw new Exception("质检单不存在");
    }
    model.setLastUpdateTime(new Date());
    if (currentUser != null) {
      model.setLastUpdateUser(currentUser.getUserId());
    }
    boolean isOk = new LambdaUpdateChainWrapper<>(baseMapper)
      .set(QualityCheckStorage::getQcSn, model.getQcSn())
      .set(QualityCheckStorage::getProductName, model.getProductName())
      .set(QualityCheckStorage::getSku, model.getSku())
      .set(QualityCheckStorage::getShop, model.getShop())
      .set(QualityCheckStorage::getFnsku, model.getFnsku())
      .set(QualityCheckStorage::getPurchaseCode, model.getPurchaseCode())
      .set(QualityCheckStorage::getBuyerName, model.getBuyerName())
      .set(QualityCheckStorage::getReceiveName, model.getReceiveName())
      .set(QualityCheckStorage::getWarehouse, model.getWarehouse())
      .set(QualityCheckStorage::getSupplier, model.getSupplier())
      .set(QualityCheckStorage::getReceiveTime, model.getReceiveTime())
      .set(
        QualityCheckStorage::getProductReceiveNum,
        model.getProductReceiveNum()
      )
      .set(QualityCheckStorage::getQcMethodType, model.getQcMethodType())
      .set(QualityCheckStorage::getQcRatePass, model.getQcRatePass())
      .set(QualityCheckStorage::getProductGoodNum, model.getProductGoodNum())
      .set(QualityCheckStorage::getProductBadNum, model.getProductBadNum())
      .set(QualityCheckStorage::getQcName, model.getQcName())
      .set(QualityCheckStorage::getQcTime, model.getQcTime())
      .set(QualityCheckStorage::getRemark, model.getRemark())
      .set(QualityCheckStorage::getQcStatus, model.getQcStatus())
      .set(QualityCheckStorage::getProductLabel, model.getProductLabel())
      .set(QualityCheckStorage::getDeliveryOrderSn, model.getDeliveryOrderSn())
      .set(QualityCheckStorage::getLastUpdateTime, model.getLastUpdateTime())
      .set(QualityCheckStorage::getLastUpdateUser, model.getLastUpdateUser())
      .set(QualityCheckStorage::getWhbCodeGoodId, model.getWhbCodeGoodId())
      .set(QualityCheckStorage::getWhbCodeBadId, model.getWhbCodeBadId())
      .eq(QualityCheckStorage::getId, model.getId())
      .update();
    if (isOk) {}
    return isOk;
  }

  /**
   * 是否走导出中心
   */
  @Override
  public boolean getBackgroundExportFlag(
    QualityCheckStorageSearchParamPo search
  ) {
    return false;
  }

  /**
   * 删除质检单
   * @param id 质检单的主键
   * @return 删除是否成功
   */
  @DataActivity(action = SysDataActivityAction.Del)
  @Override
  public boolean delete(Long id) throws Exception {
    return this.removeById(id);
  }

  /**
   * 批量删除质检单
   * @param ids 质检单的主键列表
   * @return 删除是否成功
   */
  @DataActivity(action = SysDataActivityAction.Del)
  @Override
  public boolean batchDelete(List<Long> ids) throws Exception {
    int count = 0;
    for (int i = 0; i < ids.size(); i += 2000) {
      count +=
        baseMapper.deleteBatchIds(
          ids.stream().skip(i).limit(2000).collect(Collectors.toList())
        );
    }
    return count > 0;
  }

  /**
   * 通过质检单号查询质检单主键(重复时返回最新的主键)
   */
  @Override
  public Long getIdByQcSn(String qcSn) {
    return this.baseMapper.getIdByQcSn(qcSn);
  }

  /**
   * 通过质检单号查询质检单多主键(重复时返回最新的主键)
   */
  @Override
  public List<Long> getIdsByQcSn(List<String> list) {
    return this.baseMapper.getIdsByQcSn(list);
  }

  /**
   * 通过质检单主键查询质检单号
   */
  @Override
  public String getQcSnById(Long id) {
    return this.baseMapper.getQcSnById(id);
  }

  /**
   * 通过质检单主键查询质检单号列表
   */
  @Override
  public List<String> getQcSnByIds(List<Long> ids) {
    List<Map<String, Object>> maps = this.baseMapper.getQcSnByIds(ids);
    // 将返回重新排列为输入相同顺序
    return ids
      .stream()
      .map(id -> {
        Optional<Map<String, Object>> optionalMap = maps
          .stream()
          .filter(map -> id.equals(map.get("id")))
          .findFirst();
        return optionalMap
          .map(stringObjectMap -> (String) stringObjectMap.get("qcSn"))
          .orElse(null);
      })
      .collect(Collectors.toList());
  }

  /**
   * 获取详情
   * @param id 质检单的主键
   */
  @DataActivity(action = SysDataActivityAction.View)
  @Override
  public QualityCheckStorageVo getVoById(Long id) throws Exception {
    QualityCheckStorageVo vo = this.baseMapper.selectVoById(id);
    if (vo == null) {
      return null;
    }
    return vo;
  }

  /**
   * 分页查询质检单
   * @param search 查询条件
   * @return 质检单分页查询结果
   */
  @Override
  public Page<QualityCheckStorageItemVo> pageSearch(
    QualityCheckStorageSearchParamPo search
  ) {
    Page<QualityCheckStorageItemVo> page = new Page<>();
    if (
      Objects.nonNull(search.getWfStatus()) &&
      StringUtils.hasText(search.getFormName())
    ) {
      List<WorkFlow> workFlowList = workFlowService.queryWfListByStatus(
        search.getWfStatus(),
        search.getFormName()
      );
      if (CollectionUtils.isEmpty(workFlowList)) {
        return page;
      }
      List<Long> ids = workFlowList
        .stream()
        .map(WorkFlow::getRecordId)
        .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(ids)) {
        return page;
      }
      search.setSelectedIds(ids);
    }
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    page = this.baseMapper.pageSearch(search.toPage(), search);
    List<Long> recordIds = page
      .getRecords()
      .stream()
      .map(QualityCheckStorageItemVo::getId)
      .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(recordIds)) {
      return page;
    }
    List<WorkFlow> workFlows = workFlowService.queryWfList(
      recordIds,
      Collections.singletonList(search.getFormName())
    );
    if (CollectionUtils.isEmpty(workFlows)) {
      return page;
    }
    Map<Long, Integer> flowMap = workFlows
      .stream()
      .collect(Collectors.toMap(WorkFlow::getRecordId, WorkFlow::getWfStatus));
    page
      .getRecords()
      .stream()
      .forEach(item -> {
        if (!flowMap.containsKey(item.getId())) {
          return;
        }
        item.setWfStatus(flowMap.get(item.getId()));
      });
    return page;
  }

  /**
   * 质检单快速查询选项(有缓存)
   * @param search 查询条件
   * @return 选项结果
   */
  @Override
  @Cacheable(
    value = CacheConfig.FAST,
    key = "'QualityCheckStorageOptions::' + @userInfo.userTypeAndId + '::' + #search.keyword"
  )
  public List<OptionItem<QualityCheckStorageItemVo>> searchOptions(
    QualityCheckStorageSearchParamPo search
  ) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.searchOptions(search);
  }

  /**
   * 列表查询质检单
   * @param search 查询条件
   * @return 质检单列表查询结果
   */
  @Override
  public List<QualityCheckStorageItemVo> search(
    QualityCheckStorageSearchParamPo search
  ) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.search(search);
  }

  /**
   * 查询质检单最后更新时间
   * @param search 查询条件
   * @return 质检单最后更新时间
   */
  @Override
  public Date searchLastUpdateTime(QualityCheckStorageSearchParamPo search) {
    return this.baseMapper.searchLastUpdateTime(search);
  }

  /**
   * 撤销
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了撤销操作"
  )
  @Override
  public void revocation(Long id) throws Exception {
    if (qualityCheckStorageRevocationAction == null) {
      throw new Exception("此操作当前不可用");
    }
    qualityCheckStorageRevocationAction.run(id);
  }

  /**
   * 批量撤销
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了批量撤销操作"
  )
  @Transactional(rollbackFor = Exception.class)
  @Override
  public void bulkRevocation(List<Long> ids) throws Exception {
    executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_bulkRevocation.js",
      ids,
      null,
      this
    );
  }

  /**
   * 良品转移入库
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了良品转移入库操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void stockInGood(Long id) throws Exception {
    QualityCheckStorageVo vo = getVoById(id);
    InventoryExchangeFormVo formVo = prepareStockInGood(vo);
    inventoryBusinessService.exchange(formVo);
  }

  /**
   * 准备用于 良品转移入库 的参数
   */
  protected InventoryExchangeFormVo prepareStockInGood(
    QualityCheckStorageVo vo
  ) throws Exception {
    InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
    if (ReflectUtil.hasField(QualityCheckStorageVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setSupportNegative(true);
    formVo.setFrom(TargetTypeEnum.Inspected);
    formVo.setTo(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getQcSn());
    formVo.setDocumentType("质检移库");
    if (ObjectUtils.isEmpty(vo.getLastUpdateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getLastUpdateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("出仓库 为空");
    }
    formVo.setFromStockId(vo.getWarehouse());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("入仓库 为空");
    }
    formVo.setToStockId(vo.getWarehouse());
    formVo.setModel(PatternEnum.FIFO);
    SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
    if (ObjectUtils.isEmpty(vo.getProductName())) {
      throw new Exception("产品 为空");
    }
    inventoryItem.setId(vo.getProductName());
    InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
    exchangeItem.setItem(inventoryItem);
    exchangeItem.setQty(
      String.valueOf(vo.getAllProductGoodNum()).equals("null")
        ? BigDecimal.valueOf(0)
        : BigDecimal.valueOf(vo.getAllProductGoodNum())
    );
    exchangeItem.setShopId(
      String.valueOf(vo.getShop()).equals("null")
        ? null
        : String.valueOf(vo.getShop())
    );
    exchangeItem.setFnSku(
      ObjectUtils.isEmpty(vo.getFnsku() == null ? null : vo.getFnsku().trim())
        ? null
        : String.valueOf(vo.getFnsku().trim())
    );
    exchangeItem.setCustomId(vo.getId());
    formVo.add(exchangeItem);
    return formVo;
  }

  /**
   * 次品转移入库
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了次品转移入库操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void stockInBad(Long id) throws Exception {
    QualityCheckStorageVo vo = getVoById(id);
    InventoryExchangeFormVo formVo = prepareStockInBad(vo);
    inventoryBusinessService.exchange(formVo);
  }

  /**
   * 准备用于 次品转移入库 的参数
   */
  protected InventoryExchangeFormVo prepareStockInBad(QualityCheckStorageVo vo)
    throws Exception {
    InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
    if (ReflectUtil.hasField(QualityCheckStorageVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setSupportNegative(true);
    formVo.setFrom(TargetTypeEnum.Inspected);
    formVo.setTo(TargetTypeEnum.Defect);
    formVo.setFormNum(vo.getQcSn());
    formVo.setDocumentType("质检移库");
    if (ObjectUtils.isEmpty(vo.getLastUpdateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getLastUpdateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("出仓库 为空");
    }
    formVo.setFromStockId(vo.getWarehouse());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("入仓库 为空");
    }
    formVo.setToStockId(vo.getWarehouse());
    formVo.setModel(PatternEnum.FIFO);
    SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
    if (ObjectUtils.isEmpty(vo.getProductName())) {
      throw new Exception("产品 为空");
    }
    inventoryItem.setId(vo.getProductName());
    InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
    exchangeItem.setItem(inventoryItem);
    exchangeItem.setQty(
      String.valueOf(vo.getAllProductBadNum()).equals("null")
        ? BigDecimal.valueOf(0)
        : BigDecimal.valueOf(vo.getAllProductBadNum())
    );
    exchangeItem.setShopId(
      String.valueOf(vo.getShop()).equals("null")
        ? null
        : String.valueOf(vo.getShop())
    );
    exchangeItem.setFnSku(
      ObjectUtils.isEmpty(vo.getFnsku() == null ? null : vo.getFnsku().trim())
        ? null
        : String.valueOf(vo.getFnsku().trim())
    );
    exchangeItem.setCustomId(vo.getId());
    formVo.add(exchangeItem);
    return formVo;
  }

  /**
   * 良品撤销
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了良品撤销操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void revocationGood(Long id) throws Exception {
    QualityCheckStorageVo vo = getVoById(id);
    InventoryStorageFormVo formVo = prepareRevocationGood(vo);
    inventoryBusinessService.storage(formVo);
    // 更新成功状态
    QualityCheckStorage updateStatusEntity = new QualityCheckStorage();
    updateStatusEntity.setId(id);
    updateStatusEntity.setQcStatus("3");
    updateById(updateStatusEntity);
  }

  /**
   * 准备用于 良品撤销 的参数
   */
  protected InventoryStorageFormVo prepareRevocationGood(
    QualityCheckStorageVo vo
  ) throws Exception {
    if (!"2".equals(vo.getQcStatus())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryStorageFormVo formVo = new InventoryStorageFormVo();
    if (ReflectUtil.hasField(QualityCheckStorageVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setOperate("撤消入库");
    formVo.setReverseQtySign(true);
    formVo.setSupportNegative(true);
    formVo.setTo(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getQcSn());
    formVo.setDocumentType("采购质检");
    if (ObjectUtils.isEmpty(vo.getLastUpdateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getLastUpdateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("仓库 为空");
    }
    formVo.setStockId(vo.getWarehouse());
    SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
    if (ObjectUtils.isEmpty(vo.getProductName())) {
      throw new Exception("产品 为空");
    }
    inventoryItem.setId(vo.getProductName());
    InventoryStorageVo storageItem = new InventoryStorageVo();
    storageItem.setItem(inventoryItem);
    storageItem.setQty(
      String.valueOf(vo.getAllProductGoodNum()).equals("null")
        ? BigDecimal.valueOf(0)
        : BigDecimal.valueOf(vo.getAllProductGoodNum())
    );
    storageItem.setShopId(
      String.valueOf(vo.getShop()).equals("null")
        ? null
        : String.valueOf(vo.getShop())
    );
    storageItem.setFnSku(
      ObjectUtils.isEmpty(vo.getFnsku() == null ? null : vo.getFnsku().trim())
        ? null
        : String.valueOf(vo.getFnsku().trim())
    );
    Map<Long, Integer> binds = new HashMap<>();
    binds.put(
      vo.getWhbCodeGoodId(),
      Integer.parseInt(
        String.valueOf(vo.getAllProductGoodNum()).equals("null")
          ? "0"
          : String.valueOf(vo.getAllProductGoodNum())
      )
    );
    storageItem.setBinIds(binds);
    storageItem.setFromBinIdsType(TargetTypeEnum.Normal);
    storageItem.setCustomId(vo.getId());
    formVo.add(storageItem);
    return formVo;
  }

  /**
   * 次品撤销
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了次品撤销操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void revocationBad(Long id) throws Exception {
    QualityCheckStorageVo vo = getVoById(id);
    InventoryStorageFormVo formVo = prepareRevocationBad(vo);
    inventoryBusinessService.storage(formVo);
    // 更新成功状态
    QualityCheckStorage updateStatusEntity = new QualityCheckStorage();
    updateStatusEntity.setId(id);
    updateStatusEntity.setQcStatus("2");
    updateById(updateStatusEntity);
  }

  /**
   * 准备用于 次品撤销 的参数
   */
  protected InventoryStorageFormVo prepareRevocationBad(
    QualityCheckStorageVo vo
  ) throws Exception {
    if (!"2".equals(vo.getQcStatus())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryStorageFormVo formVo = new InventoryStorageFormVo();
    if (ReflectUtil.hasField(QualityCheckStorageVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setOperate("撤消入库");
    formVo.setReverseQtySign(true);
    formVo.setSupportNegative(true);
    formVo.setTo(TargetTypeEnum.Defect);
    formVo.setFormNum(vo.getQcSn());
    formVo.setDocumentType("采购质检");
    if (ObjectUtils.isEmpty(vo.getLastUpdateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getLastUpdateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("仓库 为空");
    }
    formVo.setStockId(vo.getWarehouse());
    SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
    if (ObjectUtils.isEmpty(vo.getProductName())) {
      throw new Exception("产品 为空");
    }
    inventoryItem.setId(vo.getProductName());
    InventoryStorageVo storageItem = new InventoryStorageVo();
    storageItem.setItem(inventoryItem);
    storageItem.setQty(
      String.valueOf(vo.getAllProductBadNum()).equals("null")
        ? BigDecimal.valueOf(0)
        : BigDecimal.valueOf(vo.getAllProductBadNum())
    );
    storageItem.setShopId(
      String.valueOf(vo.getShop()).equals("null")
        ? null
        : String.valueOf(vo.getShop())
    );
    storageItem.setFnSku(
      ObjectUtils.isEmpty(vo.getFnsku() == null ? null : vo.getFnsku().trim())
        ? null
        : String.valueOf(vo.getFnsku().trim())
    );
    Map<Long, Integer> binds = new HashMap<>();
    binds.put(
      vo.getWhbCodeBadId(),
      Integer.parseInt(
        String.valueOf(vo.getAllProductBadNum()).equals("null")
          ? "0"
          : String.valueOf(vo.getAllProductBadNum())
      )
    );
    storageItem.setBinIds(binds);
    storageItem.setFromBinIdsType(TargetTypeEnum.Normal);
    storageItem.setCustomId(vo.getId());
    formVo.add(storageItem);
    return formVo;
  }

  /**
   * 良品库存转移
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了良品库存转移操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void goodExchange(Long id) throws Exception {
    QualityCheckStorageVo vo = getVoById(id);
    InventoryExchangeFormVo formVo = prepareGoodExchange(vo);
    inventoryBusinessService.exchange(formVo);
  }

  /**
   * 准备用于 良品库存转移 的参数
   */
  protected InventoryExchangeFormVo prepareGoodExchange(
    QualityCheckStorageVo vo
  ) throws Exception {
    InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
    if (ReflectUtil.hasField(QualityCheckStorageVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Normal);
    formVo.setTo(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getQcSn());
    formVo.setDocumentType("质检移库");
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("出仓库 为空");
    }
    formVo.setFromStockId(vo.getWarehouse());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("入仓库 为空");
    }
    formVo.setToStockId(vo.getWarehouse());
    formVo.setModel(PatternEnum.FIFO);
    SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
    if (ObjectUtils.isEmpty(vo.getProductName())) {
      throw new Exception("产品 为空");
    }
    inventoryItem.setId(vo.getProductName());
    InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
    exchangeItem.setItem(inventoryItem);
    exchangeItem.setQty(
      String.valueOf(vo.getAllProductGoodNum()).equals("null")
        ? BigDecimal.valueOf(0)
        : BigDecimal.valueOf(vo.getAllProductGoodNum())
    );
    exchangeItem.setShopId(
      String.valueOf(vo.getShop()).equals("null")
        ? null
        : String.valueOf(vo.getShop())
    );
    exchangeItem.setFnSku(
      ObjectUtils.isEmpty(vo.getFnsku() == null ? null : vo.getFnsku().trim())
        ? null
        : String.valueOf(vo.getFnsku().trim())
    );
    Map<Long, Integer> binds = new HashMap<>();
    binds.put(
      vo.getWaitInspection(),
      Integer.parseInt(
        String.valueOf(vo.getAllProductGoodNum()).equals("null")
          ? "0"
          : String.valueOf(vo.getAllProductGoodNum())
      )
    );
    exchangeItem.setFromBinIds(binds);
    Map<Long, Integer> toBinIds = new HashMap<>();
    toBinIds.put(
      vo.getWhbCodeGoodId(),
      Integer.parseInt(
        String.valueOf(vo.getAllProductGoodNum()).equals("null")
          ? "0"
          : String.valueOf(vo.getAllProductGoodNum())
      )
    );
    exchangeItem.setToBinIds(toBinIds);
    exchangeItem.setFromBinIdsType(TargetTypeEnum.Normal);
    exchangeItem.setToBinIdsType(TargetTypeEnum.Normal);
    exchangeItem.setCustomId(vo.getId());
    formVo.add(exchangeItem);
    return formVo;
  }

  /**
   * 次品库存转移
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了次品库存转移操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void badExchange(Long id) throws Exception {
    QualityCheckStorageVo vo = getVoById(id);
    InventoryExchangeFormVo formVo = prepareBadExchange(vo);
    inventoryBusinessService.exchange(formVo);
  }

  /**
   * 准备用于 次品库存转移 的参数
   */
  protected InventoryExchangeFormVo prepareBadExchange(
    QualityCheckStorageVo vo
  ) throws Exception {
    InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
    if (ReflectUtil.hasField(QualityCheckStorageVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Defect);
    formVo.setTo(TargetTypeEnum.Defect);
    formVo.setFormNum(vo.getQcSn());
    formVo.setDocumentType("质检移库");
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("出仓库 为空");
    }
    formVo.setFromStockId(vo.getWarehouse());
    if (ObjectUtils.isEmpty(vo.getWarehouse())) {
      throw new Exception("入仓库 为空");
    }
    formVo.setToStockId(vo.getWarehouse());
    formVo.setModel(PatternEnum.FIFO);
    SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
    if (ObjectUtils.isEmpty(vo.getProductName())) {
      throw new Exception("产品 为空");
    }
    inventoryItem.setId(vo.getProductName());
    InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
    exchangeItem.setItem(inventoryItem);
    exchangeItem.setQty(
      String.valueOf(vo.getAllProductBadNum()).equals("null")
        ? BigDecimal.valueOf(0)
        : BigDecimal.valueOf(vo.getAllProductBadNum())
    );
    exchangeItem.setShopId(
      String.valueOf(vo.getShop()).equals("null")
        ? null
        : String.valueOf(vo.getShop())
    );
    exchangeItem.setFnSku(
      ObjectUtils.isEmpty(vo.getFnsku() == null ? null : vo.getFnsku().trim())
        ? null
        : String.valueOf(vo.getFnsku().trim())
    );
    Map<Long, Integer> binds = new HashMap<>();
    binds.put(
      vo.getWaitInspection(),
      Integer.parseInt(
        String.valueOf(vo.getAllProductBadNum()).equals("null")
          ? "0"
          : String.valueOf(vo.getAllProductBadNum())
      )
    );
    exchangeItem.setFromBinIds(binds);
    Map<Long, Integer> toBinIds = new HashMap<>();
    toBinIds.put(
      vo.getWhbCodeBadId(),
      Integer.parseInt(
        String.valueOf(vo.getAllProductBadNum()).equals("null")
          ? "0"
          : String.valueOf(vo.getAllProductBadNum())
      )
    );
    exchangeItem.setToBinIds(toBinIds);
    exchangeItem.setFromBinIdsType(TargetTypeEnum.Normal);
    exchangeItem.setToBinIdsType(TargetTypeEnum.Normal);
    exchangeItem.setCustomId(vo.getId());
    formVo.add(exchangeItem);
    return formVo;
  }

  /**
   * 全部
   */
  @Override
  public List<QualityCheckStorageItemVo> allQualityCheck(
    QualityCheckStorageSearchParamPo search
  ) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.allQualityCheck(search);
  }

  /**
   * 全部分页
   */
  @Override
  public Page<QualityCheckStorageItemVo> allQualityCheckPage(
    QualityCheckStorageSearchParamPo search
  ) {
    Page<QualityCheckStorageItemVo> allQualityCheckPage = new Page<>();
    if (
      Objects.nonNull(search.getWfStatus()) &&
      StringUtils.hasText(search.getFormName())
    ) {
      List<WorkFlow> workFlowList = workFlowService.queryWfListByStatus(
        search.getWfStatus(),
        search.getFormName()
      );
      if (CollectionUtils.isEmpty(workFlowList)) {
        return allQualityCheckPage;
      }
      List<Long> ids = workFlowList
        .stream()
        .map(WorkFlow::getRecordId)
        .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(ids)) {
        return allQualityCheckPage;
      }
      search.setSelectedIds(ids);
    }
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    allQualityCheckPage =
      this.baseMapper.allQualityCheckPage(
          search.toPage(this.baseMapper.allQualityCheckCount(search)),
          search
        );
    List<Long> recordIds = allQualityCheckPage
      .getRecords()
      .stream()
      .map(QualityCheckStorageItemVo::getId)
      .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(recordIds)) {
      return allQualityCheckPage;
    }
    List<WorkFlow> workFlows = workFlowService.queryWfList(
      recordIds,
      Collections.singletonList(search.getFormName())
    );
    if (CollectionUtils.isEmpty(workFlows)) {
      return allQualityCheckPage;
    }
    Map<Long, Integer> flowMap = workFlows
      .stream()
      .collect(Collectors.toMap(WorkFlow::getRecordId, WorkFlow::getWfStatus));
    allQualityCheckPage
      .getRecords()
      .stream()
      .forEach(item -> {
        if (!flowMap.containsKey(item.getId())) {
          return;
        }
        item.setWfStatus(flowMap.get(item.getId()));
      });

    return allQualityCheckPage;
  }

  /**
   * 查询全部最后更新时间
   * @param search 查询条件
   * @return 全部最后更新时间
   */
  @Override
  public Date allQualityCheckLastUpdateTime(
    QualityCheckStorageSearchParamPo search
  ) {
    return this.baseMapper.allQualityCheckLastUpdateTime(search);
  }

  /**
   * 质检中
   */
  @Override
  public List<QualityCheckStorageItemVo> qualitying(
    QualityCheckStorageSearchParamPo search
  ) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.qualitying(search);
  }

  /**
   * 质检中分页
   */
  @Override
  public Page<QualityCheckStorageItemVo> qualityingPage(
    QualityCheckStorageSearchParamPo search
  ) {
    Page<QualityCheckStorageItemVo> qualityingPage = new Page<>();
    if (
      Objects.nonNull(search.getWfStatus()) &&
      StringUtils.hasText(search.getFormName())
    ) {
      List<WorkFlow> workFlowList = workFlowService.queryWfListByStatus(
        search.getWfStatus(),
        search.getFormName()
      );
      if (CollectionUtils.isEmpty(workFlowList)) {
        return qualityingPage;
      }
      List<Long> ids = workFlowList
        .stream()
        .map(WorkFlow::getRecordId)
        .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(ids)) {
        return qualityingPage;
      }
      search.setSelectedIds(ids);
    }
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    qualityingPage =
      this.baseMapper.qualityingPage(
          search.toPage(this.baseMapper.qualityingCount(search)),
          search
        );
    List<Long> recordIds = qualityingPage
      .getRecords()
      .stream()
      .map(QualityCheckStorageItemVo::getId)
      .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(recordIds)) {
      return qualityingPage;
    }
    List<WorkFlow> workFlows = workFlowService.queryWfList(
      recordIds,
      Collections.singletonList(search.getFormName())
    );
    if (CollectionUtils.isEmpty(workFlows)) {
      return qualityingPage;
    }
    Map<Long, Integer> flowMap = workFlows
      .stream()
      .collect(Collectors.toMap(WorkFlow::getRecordId, WorkFlow::getWfStatus));
    qualityingPage
      .getRecords()
      .stream()
      .forEach(item -> {
        if (!flowMap.containsKey(item.getId())) {
          return;
        }
        item.setWfStatus(flowMap.get(item.getId()));
      });

    return qualityingPage;
  }

  /**
   * 查询质检中最后更新时间
   * @param search 查询条件
   * @return 质检中最后更新时间
   */
  @Override
  public Date qualityingLastUpdateTime(
    QualityCheckStorageSearchParamPo search
  ) {
    return this.baseMapper.qualityingLastUpdateTime(search);
  }

  /**
   * 待审批
   */
  @Override
  public List<QualityCheckStorageItemVo> approval(
    QualityCheckStorageSearchParamPo search
  ) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.approval(search);
  }

  /**
   * 待审批分页
   */
  @Override
  public Page<QualityCheckStorageItemVo> approvalPage(
    QualityCheckStorageSearchParamPo search
  ) {
    Page<QualityCheckStorageItemVo> approvalPage = new Page<>();
    if (
      Objects.nonNull(search.getWfStatus()) &&
      StringUtils.hasText(search.getFormName())
    ) {
      List<WorkFlow> workFlowList = workFlowService.queryWfListByStatus(
        search.getWfStatus(),
        search.getFormName()
      );
      if (CollectionUtils.isEmpty(workFlowList)) {
        return approvalPage;
      }
      List<Long> ids = workFlowList
        .stream()
        .map(WorkFlow::getRecordId)
        .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(ids)) {
        return approvalPage;
      }
      search.setSelectedIds(ids);
    }
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    approvalPage =
      this.baseMapper.approvalPage(
          search.toPage(this.baseMapper.approvalCount(search)),
          search
        );
    List<Long> recordIds = approvalPage
      .getRecords()
      .stream()
      .map(QualityCheckStorageItemVo::getId)
      .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(recordIds)) {
      return approvalPage;
    }
    List<WorkFlow> workFlows = workFlowService.queryWfList(
      recordIds,
      Collections.singletonList(search.getFormName())
    );
    if (CollectionUtils.isEmpty(workFlows)) {
      return approvalPage;
    }
    Map<Long, Integer> flowMap = workFlows
      .stream()
      .collect(Collectors.toMap(WorkFlow::getRecordId, WorkFlow::getWfStatus));
    approvalPage
      .getRecords()
      .stream()
      .forEach(item -> {
        if (!flowMap.containsKey(item.getId())) {
          return;
        }
        item.setWfStatus(flowMap.get(item.getId()));
      });

    return approvalPage;
  }

  /**
   * 查询待审批最后更新时间
   * @param search 查询条件
   * @return 待审批最后更新时间
   */
  @Override
  public Date approvalLastUpdateTime(QualityCheckStorageSearchParamPo search) {
    return this.baseMapper.approvalLastUpdateTime(search);
  }

  /**
   * 已完成
   */
  @Override
  public List<QualityCheckStorageItemVo> completed(
    QualityCheckStorageSearchParamPo search
  ) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.completed(search);
  }

  /**
   * 已完成分页
   */
  @Override
  public Page<QualityCheckStorageItemVo> completedPage(
    QualityCheckStorageSearchParamPo search
  ) {
    Page<QualityCheckStorageItemVo> completedPage = new Page<>();
    if (
      Objects.nonNull(search.getWfStatus()) &&
      StringUtils.hasText(search.getFormName())
    ) {
      List<WorkFlow> workFlowList = workFlowService.queryWfListByStatus(
        search.getWfStatus(),
        search.getFormName()
      );
      if (CollectionUtils.isEmpty(workFlowList)) {
        return completedPage;
      }
      List<Long> ids = workFlowList
        .stream()
        .map(WorkFlow::getRecordId)
        .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(ids)) {
        return completedPage;
      }
      search.setSelectedIds(ids);
    }
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    completedPage =
      this.baseMapper.completedPage(
          search.toPage(this.baseMapper.completedCount(search)),
          search
        );
    List<Long> recordIds = completedPage
      .getRecords()
      .stream()
      .map(QualityCheckStorageItemVo::getId)
      .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(recordIds)) {
      return completedPage;
    }
    List<WorkFlow> workFlows = workFlowService.queryWfList(
      recordIds,
      Collections.singletonList(search.getFormName())
    );
    if (CollectionUtils.isEmpty(workFlows)) {
      return completedPage;
    }
    Map<Long, Integer> flowMap = workFlows
      .stream()
      .collect(Collectors.toMap(WorkFlow::getRecordId, WorkFlow::getWfStatus));
    completedPage
      .getRecords()
      .stream()
      .forEach(item -> {
        if (!flowMap.containsKey(item.getId())) {
          return;
        }
        item.setWfStatus(flowMap.get(item.getId()));
      });

    return completedPage;
  }

  /**
   * 查询已完成最后更新时间
   * @param search 查询条件
   * @return 已完成最后更新时间
   */
  @Override
  public Date completedLastUpdateTime(QualityCheckStorageSearchParamPo search) {
    return this.baseMapper.completedLastUpdateTime(search);
  }

  /**
   * 已撤销
   */
  @Override
  public List<QualityCheckStorageItemVo> revoked(
    QualityCheckStorageSearchParamPo search
  ) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.revoked(search);
  }

  /**
   * 已撤销分页
   */
  @Override
  public Page<QualityCheckStorageItemVo> revokedPage(
    QualityCheckStorageSearchParamPo search
  ) {
    Page<QualityCheckStorageItemVo> revokedPage = new Page<>();
    if (
      Objects.nonNull(search.getWfStatus()) &&
      StringUtils.hasText(search.getFormName())
    ) {
      List<WorkFlow> workFlowList = workFlowService.queryWfListByStatus(
        search.getWfStatus(),
        search.getFormName()
      );
      if (CollectionUtils.isEmpty(workFlowList)) {
        return revokedPage;
      }
      List<Long> ids = workFlowList
        .stream()
        .map(WorkFlow::getRecordId)
        .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(ids)) {
        return revokedPage;
      }
      search.setSelectedIds(ids);
    }
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    revokedPage =
      this.baseMapper.revokedPage(
          search.toPage(this.baseMapper.revokedCount(search)),
          search
        );
    List<Long> recordIds = revokedPage
      .getRecords()
      .stream()
      .map(QualityCheckStorageItemVo::getId)
      .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(recordIds)) {
      return revokedPage;
    }
    List<WorkFlow> workFlows = workFlowService.queryWfList(
      recordIds,
      Collections.singletonList(search.getFormName())
    );
    if (CollectionUtils.isEmpty(workFlows)) {
      return revokedPage;
    }
    Map<Long, Integer> flowMap = workFlows
      .stream()
      .collect(Collectors.toMap(WorkFlow::getRecordId, WorkFlow::getWfStatus));
    revokedPage
      .getRecords()
      .stream()
      .forEach(item -> {
        if (!flowMap.containsKey(item.getId())) {
          return;
        }
        item.setWfStatus(flowMap.get(item.getId()));
      });

    return revokedPage;
  }

  /**
   * 查询已撤销最后更新时间
   * @param search 查询条件
   * @return 已撤销最后更新时间
   */
  @Override
  public Date revokedLastUpdateTime(QualityCheckStorageSearchParamPo search) {
    return this.baseMapper.revokedLastUpdateTime(search);
  }

  /**
   * 质检审核
   * @param args 参数
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Object qualityInspectionAudit(JSONObject args) throws Exception {
    executeScriptEngine.requestParamUnion(args);
    return executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_QualityInspectionAudit.js",
      args,
      this
    );
  }

  /**
   * 取消质检
   * @param args 参数
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Object cancelQualityInspection(JSONObject args) throws Exception {
    executeScriptEngine.requestParamUnion(args);
    return executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_CancelQualityInspection.js",
      args,
      this
    );
  }

  /**
   * 更新库存
   * @param args 参数
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Object updateInventoryPartStatistics(JSONObject args)
    throws Exception {
    executeScriptEngine.requestParamUnion(args);
    return executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_UpdateInventoryPartStatistics.js",
      args,
      this
    );
  }

  /**
   * 完成质检
   * @param args 参数
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Object completeQualityInspection(JSONObject args) throws Exception {
    executeScriptEngine.requestParamUnion(args);
    return executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_CompleteQualityInspection.js",
      args,
      this
    );
  }

  /**
   * 详情页数据（废弃）
   * @param args 参数
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Object detailPageData(JSONObject args) throws Exception {
    executeScriptEngine.requestParamUnion(args);
    return executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_DetailPageData.js",
      args,
      this
    );
  }

  /**
   * 质检历史
   * @param args 参数
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Object qualityInspectionHistory(JSONObject args) throws Exception {
    executeScriptEngine.requestParamUnion(args);
    return executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_QualityInspectionHistory.js",
      args,
      this
    );
  }

  /**
   * 关联单据（收货单）
   * @param args 参数
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Object associatedDocuments(JSONObject args) throws Exception {
    executeScriptEngine.requestParamUnion(args);
    return executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_AssociatedDocuments.js",
      args,
      this
    );
  }

  /**
   * 关联单据（入库单）
   * @param args 参数
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Object relatedDocuments(JSONObject args) throws Exception {
    executeScriptEngine.requestParamUnion(args);
    return executeScriptEngine.callJsInResource(
      "scripts/QualityCheckStorage_RelatedDocuments.js",
      args,
      this
    );
  }
}
